// extjs
Ext.ns("K.Ext");
K.Ext.Panel = Ext.extend(Ext.Panel, {
	animCollapse : false,
	showLoadIndicator : false,
	initComponent : function() {
		K.Ext.Panel.superclass.initComponent.call(this);
		this.on("afterrender", function() {
			if (!this.showLoadIndicator) {
				this.getUpdater().showLoadIndicator = false;
			}
		});
	},
	random : true,
	load : function() {
		var um = this.body.getUpdater(), url = arguments[0] ? arguments[0].url : false;
		if (url) {
			arguments[0].url = this.random && url ? K.randomUrl(url) : url;
		}
		um.update.apply(um, arguments);
		return this;
	}
});
K.Ext.TabPanel = Ext.extend(Ext.TabPanel, {});

Ext.ns("K.Ext.grid");
K.Ext.grid.GridPanel = Ext.extend(Ext.grid.GridPanel, {
// loadMask : true
});

Ext.ns("K.Ext.tree");
K.Ext.tree.TreeLoader = function(config) {
	K.Ext.tree.TreeLoader.superclass.constructor.call(this, config);
	this.on("beforeload", function(treeLoader, node) {
		this.baseParams.$ajax_current_time = K.currentTime();
	}, this);
};
Ext.extend(K.Ext.tree.TreeLoader, Ext.tree.TreeLoader, {
	// 异步加载节点时处理fastjson的$ref, $ref是当前加载时返回根对象,
	// 处理完后,指向$ref是同一个对象,所以修改时不必担心
	processResponse : function(response, node, callback, scope) {
		try {
			var o = response.responseData || Ext.decode(response.responseText);
			if (!o) {
				return;
			}
			if (K.fastjson) {
				K.fastjson.convertRefValue(o);
			}
			o = this.filterTreeData(o);
			node.beginUpdate();
			for ( var i = 0, len = o.length; i < len; i++) {
				var n = this.createNode(o[i]);
				if (n) {
					node.appendChild(n);
				}
			}
			node.endUpdate();
			this.runCallback(callback, scope || node, [ node ]);
		} catch (e) {
			alert("treeloader exception:" + e.message);
			this.handleFailure(response);
			throw e;
		}
	},
	responseToJson : function(txt, response) {
		return response.responseData || Ext.decode(response.responseText);
	},

	filterTreeData : function(data) {
		return data;
	}
});
/**
 * 修改树被渲染然后，自动去渲染ROOT节点(ROOT为空)的BUG
 */
K.Ext.tree.TreePanel = Ext.extend(Ext.tree.TreePanel, {
	afterRender : function() {
		Ext.tree.TreePanel.superclass.afterRender.call(this);
		if (this.root) {
			this.root.render();
		}
	}
});
// FIX: TreeNode,动态追加子节点后,本节点的leaf没有被改,导致updateExpandIcon无用
Ext.override(Ext.tree.TreeNode, {
	appendChild : function(n) {
		if (!n.render && !Ext.isArray(n)) {
			n = this.getLoader().createNode(n);
		}
		var node = Ext.tree.TreeNode.superclass.appendChild.call(this, n);
		if (node && this.childrenRendered) {
			node.render();
		}
		this.leaf = false; // <--
		this.ui.updateExpandIcon();
		return node;
	}
});
K.Ext.tree.TreeNode = Ext.extend(Ext.tree.TreeNode, {});
K.Ext.tree.AsyncTreeNode = Ext.extend(Ext.tree.AsyncTreeNode, {});

Ext.ns("K.Ext.data");
/**
 * 添加$ref转换功能,若列表需要转换$ref,配置convertRef:true.
 */
K.Ext.data.JsonListStore = Ext.extend(Ext.data.JsonStore, {
	paramNames : { // 设置传递的分页参数名
		start : '$page_start',
		limit : '$page_size'
	},
	constructor : function(config) {
		config.totalProperty = config.totalProperty || "parameters.pagination.totalResults";
		Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(config, {
			reader : new K.Ext.data.JsonListReader(config)
		}));
	}
});
Ext.reg('jsonliststore', K.Ext.data.JsonListStore);
K.Ext.data.JsonListReader = Ext.extend(Ext.data.JsonReader, {
	read : function(response) {
		var json = response.responseText;
		var o = Ext.decode(json);
		if (!o) {
			throw {
				message : 'JsonReader.read: Json object not found'
			};
		}
		if (K.fastjson && this.meta.convertRef === true) {
			K.fastjson.convertRefValue(o);
		}
		return this.readRecords(o);
	}
});
K.Ext.data.JsonStore = Ext.extend(Ext.data.JsonStore, {
	constructor : function(config) {
		Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(config, {
			reader : new K.Ext.data.JsonStoreReader(config)
		}));
	}
});
K.Ext.data.JsonStoreReader = Ext.extend(Ext.data.JsonReader, {
	read : function(response) {
		var json = response.responseText;
		var o = Ext.decode(json);
		if (!o) {
			throw {
				message : 'JsonReader.read: Json object not found'
			};
		}
		if (K.fastjson && this.meta.convertRef === true) {
			K.fastjson.convertRefValue(o);
		}
		return this.readRecords(o);
	}
});

window.$DefaultPageSize = 20;
K.Ext.PagingToolbar = Ext.extend(Ext.PagingToolbar, {
	pageSize : $DefaultPageSize,
	displayInfo : true,
	displayMsg : '显示：{0} 到 {1} 条 &nbsp;&nbsp;&nbsp;&nbsp;总：{2} 条',
	emptyMsg : "没任何记录",
	bindStore : function(store, initial) {
		if (!store) { // 获取最近父容器的store
			for ( var p = this.ownerCt; (p != null) && !(store = p.store); p = p.ownerCt)
				;
		}
		return K.Ext.PagingToolbar.superclass.bindStore.call(this, store, initial);
	},
	listeners : {
		"beforechange" : function(page, params) {
			if (this.store.lastOptions.params) {
				var pn = this.getParams();
				delete this.store.lastOptions.params[pn.start];
				delete this.store.lastOptions.params[pn.limit];
				$.extend(params, this.store.lastOptions.params);
			}
			return true;
		}
	}
});
Ext.reg('pagination', K.Ext.PagingToolbar);
K.Ext.grid.CheckboxSelectionModel = Ext.extend(Ext.grid.CheckboxSelectionModel, {
	width : 25
});
// destroy components
K.destroyComponents = function(components) {
	if (components) {
		components = components instanceof Array ? components : [ components ];
		$.each(components, function(i, component) {
			if (component && component.destroy) {
				component.destroy();
			}
		});
	}
};
// ..

K.json = function(json) {
	return Ext.decode(json);
};

// delegate function
K.createDelegate = function(fn, optional, args, booleanAppendArgs) {
	return Ext.util.Functions.createDelegate(fn, optional, args, booleanAppendArgs);
};
// wrap function
K.createInterceptor = function(origFn, newFn, scope) {
	return Ext.createInterceptor(origFn, newFn, scope);
};

/**
 * 统一使用Window<br>
 * 修改window在拖拽时在IE8会闪的问题, 每次加载,自动在URL中添加随机数
 */
K.Ext.Window = Ext.extend(Ext.Window, {
	modal : true,
	padding : "3px",
	iconCls : "grid-icon",
	bodyStyle : "background:#ffffff;",
	ghost : function(cls) {
		var ghost = this.createGhost(cls);
		this.el.hide();
		this.activeGhost = ghost;
		return ghost;
	},
	createGhost : function(cls, useShim, appendTo) {
		var el = document.createElement('div');
		el.className = 'x-panel-ghost ' + (cls ? cls : '');
		if (this.header) {
			el.appendChild(this.el.dom.firstChild.cloneNode(true));
		}
		Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
		el.style.width = this.el.dom.offsetWidth + 'px';

		var box = this.getBox(true);
		Ext.fly(el).setLeftTop(box.x, box.y);
		Ext.fly(el).setWidth(box.width);

		if (!appendTo) {
			this.container.dom.appendChild(el);
		} else {
			Ext.getDom(appendTo).appendChild(el);
		}
		if (useShim !== false && this.el.useShim !== false) {
			var layer = new Ext.Layer({
				shadow : false,
				useDisplay : true,
				constrain : false
			}, el);
			layer.show();
			return layer;
		} else {
			return new Ext.Element(el);
		}
	},
	doRenderLoad : function(params) {
		if (this.loadOptions.url) {
			this.load({
				method : this.loadOptions.method || "GET",
				url : this.loadOptions.url,
				params : $.extend(true, {}, this.loadOptions.params, params)
			});
		}
	},
	reload : function(params) { // 让window也支持reload
		if (this.lastLoadParams) {
			this.doRenderLoad(this.lastLoadParams);
		}
	},
	listeners : {
		render : function() {
			if (this.loadOptions && false !== this.loadOptions.autoLoad) {
				this.doRenderLoad();
			} else if (this.loadUrl) {
				this.loadOptions = {
					url : this.loadUrl
				};
				this.doRenderLoad();
			}
		}
	},
	load : function() {
		var um = this.body.getUpdater();
		this.lastLoadParams = arguments[0];

		if (arguments.length) {
			if (typeof (arguments[0]) == "object") {
				arguments[0].text = window.defaultLoadMaskHtml.replace("${text}", arguments[0].text || window.defaultLoadMaskText);
			} else {
				arguments[0] = {
					url : arguments[0],
					text : window.defaultLoadMaskHtml.replace("${text}", window.defaultLoadMaskText)
				};
			}
		}

		if (arguments[0].scripts !== false) {
			arguments[0].scripts = true;
		}

		arguments[0].url = K.randomUrl(arguments[0].url);
		um.update.apply(um, arguments);
		return this;
	}
});

window.$targetElementId = window.$targetElementId || "target";
K.Ext.MainPanel = Ext.extend(Ext.Container, {
	border : false,
	layout : "border",
	cusWidth : false,
	cusHeight : false,
	constructor : function(config) {
		if (config && !!!config.autoRenderToTarget) {
			this.renderTo = $targetElementId;
		}
		K.Ext.MainPanel.superclass.constructor.call(this, config);
	},
	initComponent : function() {
		K.Ext.MainPanel.superclass.initComponent.call(this);
		Ext.EventManager.onWindowResize(this.fireResize, this);
	},
	fireResize : function(w, h) {
		this.setHeight(h);
		this.setWidth(w);
		this.fireEvent('resize', this, w, h, w, h);
	},
	listeners : {
		beforerender : function() {
			if (!!!this.autoRenderToTarget) {
				if (!this.cusWidth) {
					this.setWidth(window.$targetWidth);
				}
				if (!this.cusHeight) {
					this.setHeight(window.$targetHeight);
				}
			}
		}
	}
});

// combos
K.Ext.ComboTree = Ext.extend(Ext.form.ComboBox, {
	constructor : function(config) {
		this.config = config;
		Ext.apply(this, config);
		Ext.BoxComponent.superclass.constructor.apply(this, arguments);
	},
	initComponent : function() {
		this.initTree();
		K.Ext.ComboTree.superclass.initComponent.apply(this, arguments);
	},
	// defaults
	store : store = new Ext.data.SimpleStore({
		fields : [],
		data : [ [] ]
	}),
	triggerAction : 'all',
	mode : 'local', // private
	typeAhead : true,
	forceSelection : true,
	selectOnFocus : false,
	editable : false,
	assertValue : Ext.emptyFn,
	emptyText : '请选择',
	valueField : "id",
	displayField : "text",
	initTree : function() {
		var me = this, config = me.config;
		if (!me.tree) {
			var loader = config.loader;
			if (!loader) {
				if (!config.url) {
					alert("no a url , can't create a tree loader !!");
					return;
				}

				var loaderOptions = Ext.apply(Ext.apply({
					requestMethod : "GET"
				}, config), config.loaderConfig);

				if (K.Ext.tree && K.Ext.tree.TreeLoader) {
					loader = new K.Ext.tree.TreeLoader(loaderOptions);
				} else {
					loader = new Ext.tree.TreeLoader(loaderOptions);
				}
			}

			var options = {
				useArrows : false,
				autoScroll : true,
				animate : true,
				containerScroll : true,
				border : false,
				loader : loader,
				root : {
					text : 'ROOT'
				},
				rootVisible : true
			};

			Ext.apply(options, config);
			Ext.apply(options, config.treeConfig);

			delete options.applyTo;
			me.tree = new Ext.tree.TreePanel(options);
		}

		me.treeDomId = Ext.id() + "-comboTree-id";
		me.tpl = new Ext.Template('<div style="height:' + this.maxHeight + 'px"><div id="' + me.treeDomId + '"></div></div>');

		me.tree.on('click', function(node) {
			me.setValue(node);
			me.collapse();
		});
		me.tree.on('expandnode', function(node) {
			if (node.hasChildNodes()) {
				if (me.hiddenField) {
					$.each(node.childNodes, function(i, n) {
						if (me.hiddenField.value == n.attributes[me.valueField]) {
							me.tree.getSelectionModel().select(n);
						}
					});
				}
			}
		});
	},
	setValue : function(value) {
		if (typeof value == 'string') { // form initValue
			this.value = value;
		} else { // tree's node
			this.value = value[this.displayField];
			this.lastSelectionText = this.value;
			if (this.hiddenField) {
				this.hiddenField.value = value.attributes[this.valueField];
			}
		}

		Ext.form.ComboBox.superclass.setValue.call(this, this.value);
		return;
	},
	initValue : function() {
		Ext.form.ComboBox.superclass.initValue.call(this);
		if (this.hiddenField && this.hiddenValue) {
			this.hiddenField.value = this.hiddenValue;
		}
	},
	expand : function() {
		if (!this.tree.rendered) {
			this.tree.height = this.maxHeight;
			this.tree.border = false;
			this.tree.autoScroll = true;
			this.tree.render(this.treeDomId);
		}
		K.Ext.ComboTree.superclass.expand.call(this);
	},
	collapse : function() {
		if (!this.isExpanded()) {
			return;
		}
		this.list.hide();
		Ext.getDoc().un('mousewheel', this.collapseIf, this);
		Ext.getDoc().un('mousedown', this.collapseIf, this);
		this.fireEvent('collapse', this);
	},
	onViewClick : function(doFocus) {
		// nothing
		if (doFocus !== false) {
			// this.el.focus();
		}
	},
	onRender : function(ct, position) {
		if (this.hiddenName && !Ext.isDefined(this.submitValue)) {
			this.submitValue = false;
		}
		Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
		if (this.hiddenName && !this.hiddenField) {// ADD
			this.hiddenField = this.el.insertSibling({
				tag : 'input',
				type : this.debug ? 'text' : 'hidden',
				name : this.hiddenName,
				id : (this.hiddenId || Ext.id())
			}, 'before', true);

		}
		if (Ext.isGecko) {
			this.el.dom.setAttribute('autocomplete', 'off');
		}

		if (!this.lazyInit) {
			this.initList();
		} else {
			this.on('focus', this.initList, this, {
				single : true
			});
		}
	}
});

// flys
K.Ext.flyRecord = function(record) {
	if (window.$flyRecord) {
		window.$flyRecord.record = record;
		return window.$flyRecord;
	}
	function set() {
		if (arguments.length == 0) {
			return;
		}
		if (arguments.length == 1) {
			var me = this, obj = arguments[0];
			$.each(obj, function(k, v) {
				if (me.record.fields.get(k)) {
					me.record.set(k, v);
				}
			});
		} else if (arguments.length == 2 && typeof arguments[0] == 'object') {
			var me = this, obj = arguments[0], filter = arguments[1];
			filter = (filter instanceof Array) ? filter : [ filter ];
			if (filter.length != 0) {
				$.each(filter, function(i, v) {
					if (me.record.fields.get(v)) {
						me.record.set(v, obj[v]);
					}
				});
			} else {
				$.each(obj, function(k, v) {
					if (me.record.fields.get(k)) {
						me.record.set(k, v);
					}
				});
			}
		} else {
			var len = arguments.length % 2 == 0 ? arguments.length : arguments.length - 1;
			for ( var i = 0; i < len; i++) {
				if (this.record.fields.get(arguments[i])) {
					this.record.set(arguments[i], arguments[++i]);
				}
			}
		}
		return this;
	}
	function commit(silent) {
		this.record.commit(silent);
		return this;
	}
	function getRecord() {
		return this.record;
	}
	return window.$flyRecord = {
		record : record,
		getRecord : getRecord,
		set : set,
		commit : commit
	};
};
K.Ext.flyTree = function(treePanel) {
	if (window.$flyTree) {
		window.$flyTree.treePanel = treePanel;
		return window.$flyTree;
	}
	function getNodeById(id) {
		id = typeof id == "object" ? id.id : id;
		var selectNode = this.treePanel.getSelectionModel().getSelectedNode();
		if (selectNode && id == selectNode.id) {
			return selectNode;
		}
		return this.treePanel.getRootNode().findChildBy(function(node) {
			if (node.id == id) {
				return true;
			}
		}, this, true);
	}
	function setNodeText(id, text) {
		if (arguments.length == 1 && typeof arguments[0] == "object") {
			this.setNodeText(id.id, id);
		} else if (arguments.length == 2) {
			var node = this.getNodeById(id);
			if (node) {
				text = typeof text == "object" ? text.text || text.name : text;
				node.setText(text);
			}
		}
		return this;
	}
	function removeById(id) { // 多个ID使用','分割
		if (K.isBlank(id)) {
			return;
		}
		id = id.split(","), me = this;
		$.each(id, function(i, v) {
			var node = me.getNodeById(v);
			if (node) {
				node.remove();
			}
		});
	}
	// 删除后按下上父的选择规则进行选择
	function autoSelectByDelete(id) {
		if (K.isBlank(id)) {
			return;
		}
		var node = this.getNodeById(id), parentNode = node.parentNode, nextSibling = node.nextSibling, previousSibling = node.previousSibling;
		node.remove();
		if (nextSibling) {
			nextSibling.select();
		} else if (previousSibling) {
			previousSibling.select();
		} else if (parentNode) {
			parentNode.select();
		}
	}
	function updateIcon(id, iconCls) {
		if (K.isBlank(id)) {
			return;
		}
		var node = this.getNodeById(id);
		if (node) {
			$(node.ui.getIconEl()).removeClass(node.attributes.iconCls).addClass(iconCls);
			node.attributes.iconCls = iconCls;
		}
	}
	return window.$flyTree = {
		treePanel : treePanel,
		getNodeById : getNodeById,
		setNodeText : setNodeText,
		removeById : removeById,
		autoSelectByDelete : autoSelectByDelete,
		updateIcon : updateIcon
	};
};

K.Ext.flyStore = function(store) {
	if (window.$flyStore) {
		window.$flyStore.store = store;
		return window.$flyStore;
	}
	/**
	 * 按ID删除记录
	 */
	function removeRecordById(ids) {
		if (!ids) {
			return [];
		}
		var me = this, idsArr = ids.split(","), delRecs = [];
		$.each(idsArr, function(i, id) {
			delRecs.push(me.store.getById(id));
			me.store.remove(delRecs[delRecs.length - 1]);
		});
		return delRecs;
	}
	/**
	 * 升序排序
	 */
	function sortIndexByIds(ids) {
		if (K.isBlank(ids)) {
			return [];
		}
		var arr = ids.split(",");
		var me = this, indexs = [];
		$.each(arr, function(i, id) {
			indexs.push(me.store.indexOfId(id));
		});
		indexs.sort(function(a, b) {
			return a - b;
		});
		return indexs;
	}
	/**
	 * 删除记录后自动选择其他记录,返回被删除的记录数组
	 */
	function autoSelectByDelete(selModel, delIds) {
		if (K.isBlank(delIds)) {
			return;
		}

		var theTodoSelectRecord = false, sortedIndexs = this.sortIndexByIds(delIds);
		if (sortedIndexs.length != 0) {
			var max = sortedIndexs[sortedIndexs.length - 1], min = sortedIndexs[0];
			if (sortedIndexs.length == this.store.getCount()) { // 被删除完
				theTodoSelectRecord = false;
			} else {
				theTodoSelectRecord = min == 0 ? 0 : (max + 1 == this.store.getCount()/* 末尾记录 */
				&& max - min + 1 == sortedIndexs.length/* 中间是不存在记录 */) ? min - 1 : min;
			}
		}
		var rs = this.removeRecordById(delIds);
		if (theTodoSelectRecord !== false) {
			selModel.selectRecords([ this.store.getAt(theTodoSelectRecord) ]);
		}
		return rs;
	}
	function add(records) {
		records = records instanceof Array ? records : [ records ];
		var me = this;
		$.each(records, function(i, v) {
			if (me.store.getById(v.id) == null) {
				me.store.add(v);
			}
		});
	}
	return window.$flyStore = {
		store : store,
		sortIndexByIds : sortIndexByIds,
		autoSelectByDelete : autoSelectByDelete,
		removeRecordById : removeRecordById,
		add : add
	};
};

// mini
K.MiniTrigger = Ext.extend(Ext.form.TriggerField, {
	emptyText : "---请选择---",
	initComponent : function() {
		K.MiniTrigger.superclass.initComponent.call(this);
		this.addEvents("triggerClick");
		if (this.click) {
			this.on("triggerClick", this.click, this);
		}
	},
	onTriggerClick : function() {
		this.fireEvent("triggerClick", this);
	},
	beforeBlur : function() {
		var v = this.el.dom.value;
		if (K.isBlank(v) && this.hiddenField) {
			this.hiddenField.value = "";
		}
	}
});

// renderer
K.renders = {
	enableRender : function(value) {
		return (value == 1 || value === true) ? "启用" : "停用";
	},
	itemEnableRender : function(item, key) {
		return enableRender(item[key]);
	},
	lockRender : function(value) {
		return (value == 1 || value === true) ? "正常" : "被锁";
	},
	itemLockRender : function(item, key) {
		return lockRender(item[key]);
	}
};

// framework
Ext.ns("K.framework");
K.FrameworkClass = Ext.extend(Ext.util.Observable, {
	lazyInit : false,
	constructor : function(config) {
		this.invokeConstructorMethod(config);

		if (this.purviewConfig && !this.skipPurview) {
			var clazz = this.getClass();
			if (clazz.purview && !clazz.purview()) {
				return false; // 无权访问
			}
		}

		K.FrameworkClass.superclass.constructor.call(this, config);

		if (!this.lazyInit && this.initialize) {
			this.initialize();
		}
	},
	invokeConstructorMethod : function() {
		var method = this[this.simpleClassName];
		if (method) {
			method.apply(this, arguments);
		}// else Ext.apply(this, config);
	}
});
K.framework.BaseView = Ext.extend(K.FrameworkClass, {});
K.framework.BaseController = Ext.extend(K.FrameworkClass, {
	renderView : function(c) {
		if (this.view && this.view.render) {
			this.view.render(c);
		}
	}
});
K.framework.Field = Ext.extend(K.FrameworkClass, {});
K.framework.DataInterface = Ext.extend(K.FrameworkClass, {});
K.framework.BaseService = Ext.extend(K.FrameworkClass, {});
K.framework.Meta = Ext.extend(K.FrameworkClass, {});
K.framework.Event = Ext.extend(K.FrameworkClass, {});
K.def = function(className, config) {
	return _defClass(className, K.FrameworkClass, config);
};
K.defDI = K.defDataInterface = function(className, config) {
	return _defClass(className, K.framework.DataInterface, config);
};
K.defField = K.defDataInterface = function(className, config) {
	return _defClass(className, K.framework.Field, config);
};
K.defView = function(className, config) {
	return _defClass(className, K.framework.BaseView, config);
};
K.defCtrl = function(className, config) {
	return _defClass(className, K.framework.BaseController, config);
};
K.defService = function(className, config) {
	return _defClass(className, K.framework.BaseService, config);
};
K.defMeta = function(className, config) {
	return _defClass(className, K.framework.Meta, config);
};

K.$frameworkClass = {};
K.isFrameworkClass = function(_class) {
	return _class != null ? (_class.$frameworkClassName != null) : false;
};
K.lookUpFrameworkInstance = function(c) {
	if (!c) {
		return null;
	}
	var cn = c;
	if (cn instanceof Function && K.isFrameworkClass(c)) {
		cn = cn.$frameworkClassName;
	}
	return K.$frameworkClass[cn];
};
K.registerFrameworkInstance = function(instance) {
	if (!instance) {
		return false;
	}
	K.$frameworkClass[instance.getClass().className] = instance;
	return true;
};
K.extend(Function.prototype, {
	instance : $$instance,
	newInstance : $$newInstance
});
// new instance
function $$newInstance(config) {
	if (!K.isFrameworkClass(this)) {
		return null;
	}
	var instance = null;
	if (this.$frameworkClassName) {
		instance = eval("new " + this.$frameworkClassName + "(config);");
	}
	return instance;
}
// singleton
function $$instance(config) {
	if (!K.isFrameworkClass(this)) {
		return null;
	}
	var instance = K.lookUpFrameworkInstance(this);
	if (!instance) {
		instance = this.newInstance(config);
		K.registerFrameworkInstance(instance);
	}
	return instance;
}

function _defClass(className, superClass, config) {
	Ext.ns(className);
	var statics = config.statics;
	delete config.statics;
	var _class = Ext.extend(superClass, K.extend(config, {
		className : className,
		simpleClassName : (function(className) {
			var lpIdx = className.lastIndexOf(".");
			return lpIdx != -1 ? className.substr(lpIdx + 1) : className;
		})(className),
		getClass : function() {
			return eval(this.className); // fn
		}
	}));
	K.extend(_class, {
		$frameworkClassName : className,
		className : className
	});
	K.extend(_class, statics || {});
	if (config.purviewConfig) {
		_class.hasPurview = function(purviewCode) {
			return hasPurview(purviewCode);
		};
		var pconfig = config.purviewConfig;
		$.each(pconfig, function(k, v) {
			dynamicFunction(_class, "purview", k == "view" ? "" : K.capitalize(k), (function(purviewCode) {
				return function() {
					return this.hasPurview(purviewCode);
				};
			}).call(_class, v));
		});
	}
	eval(className + " = _class;");
	return _class;

	function dynamicFunction(_class, prefix, fnName, fn) {
		eval("_class." + prefix + fnName + " = fn");
	}

	function hasPurview(purviewCode) {
		if (window.hasPurview) {
			window.checkedPurviewMap = window.checkedPurviewMap || {};
			if (window.checkedPurviewMap[purviewCode] == undefined) {
				window.checkedPurviewMap[purviewCode] = window.hasPurview(purviewCode);
			}
			return window.checkedPurviewMap[purviewCode];
		}
		return false;
	}
}
window.E = _defClass("E", K.framework.Event, {}).instance();
// end framework
